package com.beauty.product.service.impl;

import com.beauty.product.dto.CategoryDto;
import com.beauty.product.entity.Category;
import com.beauty.product.repository.CategoryRepository;
import com.beauty.product.service.CategoryService;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CategoryServiceImpl implements CategoryService {

    private final CategoryRepository categoryRepository;

    @Override
    @Transactional
    public CategoryDto createCategory(CategoryDto categoryDto) {
        Category category = convertToEntity(categoryDto);
        category.setCreatedTime(LocalDateTime.now());
        category = categoryRepository.save(category);
        return convertToDto(category);
    }

    @Override
    public CategoryDto getCategoryById(Long id) {
        Category category = categoryRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("分类不存在: " + id));
        return convertToDto(category);
    }

    @Override
    public CategoryDto getCategoryByName(String name) {
        Category category = categoryRepository.findByName(name)
                .orElseThrow(() -> new EntityNotFoundException("分类不存在: " + name));
        return convertToDto(category);
    }

    @Override
    public List<CategoryDto> getRootCategories() {
        return categoryRepository.findByParentIdOrderBySort(null)
                .stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryDto> getSubcategories(Long parentId) {
        return categoryRepository.findByParentIdOrderBySort(parentId)
                .stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryDto> getCategoriesByLevel(Integer level) {
        return categoryRepository.findByLevel(level)
                .stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryDto> getAllCategories() {
        return categoryRepository.findAll()
                .stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<CategoryDto> getCategoryTree() {
        List<Category> allCategories = categoryRepository.findAll();
        List<CategoryDto> rootCategories = new ArrayList<>();
        Map<Long, List<CategoryDto>> childrenMap = new HashMap<>();

        // 将所有分类按照父ID分组
        for (Category category : allCategories) {
            CategoryDto dto = convertToDto(category);
            if (category.getParentId() == null) {
                rootCategories.add(dto);
            } else {
                List<CategoryDto> children = childrenMap.computeIfAbsent(
                        category.getParentId(), k -> new ArrayList<>());
                children.add(dto);
            }
        }

        // 为每个分类设置子分类
        for (CategoryDto rootCategory : rootCategories) {
            setChildren(rootCategory, childrenMap);
        }

        return rootCategories;
    }

    private void setChildren(CategoryDto parent, Map<Long, List<CategoryDto>> childrenMap) {
        List<CategoryDto> children = childrenMap.get(parent.getId());
        if (children != null) {
            parent.setChildren(children);
            for (CategoryDto child : children) {
                setChildren(child, childrenMap);
            }
        }
    }

    @Override
    @Transactional
    public CategoryDto updateCategory(Long id, CategoryDto categoryDto) {
        Category category = categoryRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("分类不存在: " + id));

        category.setName(categoryDto.getName());
        category.setDescription(categoryDto.getDescription());
        category.setParentId(categoryDto.getParentId());
        category.setLevel(categoryDto.getLevel());
        category.setSort(categoryDto.getSort());
        category.setIcon(categoryDto.getIcon());
        category.setIsShow(categoryDto.getIsShow());
        category.setUpdatedTime(LocalDateTime.now());

        category = categoryRepository.save(category);
        return convertToDto(category);
    }

    @Override
    @Transactional
    public void deleteCategory(Long id) {
        if (!categoryRepository.existsById(id)) {
            throw new EntityNotFoundException("分类不存在: " + id);
        }
        
        // 检查是否有子分类
        List<Category> children = categoryRepository.findByParentIdOrderBySort(id);
        if (!children.isEmpty()) {
            throw new IllegalStateException("该分类下有子分类，请先删除子分类");
        }
        
        categoryRepository.deleteById(id);
    }

    private CategoryDto convertToDto(Category category) {
        CategoryDto dto = new CategoryDto();
        dto.setId(category.getId());
        dto.setName(category.getName());
        dto.setDescription(category.getDescription());
        dto.setParentId(category.getParentId());
        dto.setLevel(category.getLevel());
        dto.setSort(category.getSort());
        dto.setIcon(category.getIcon());
        dto.setIsShow(category.getIsShow());
        dto.setCreatedTime(category.getCreatedTime());
        dto.setUpdatedTime(category.getUpdatedTime());
        return dto;
    }

    private Category convertToEntity(CategoryDto dto) {
        Category category = new Category();
        category.setId(dto.getId());
        category.setName(dto.getName());
        category.setDescription(dto.getDescription());
        category.setParentId(dto.getParentId());
        category.setLevel(dto.getLevel());
        category.setSort(dto.getSort());
        category.setIcon(dto.getIcon());
        category.setIsShow(dto.getIsShow() != null ? dto.getIsShow() : true);
        category.setCreatedTime(dto.getCreatedTime() != null ? dto.getCreatedTime() : LocalDateTime.now());
        category.setUpdatedTime(dto.getUpdatedTime());
        return category;
    }
} 